package main.controller;

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import main.*;
import main.database.*;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.eq;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

class RankPageIndicator {
    public boolean hasNext;
    public boolean hasPrevious;
    public long totalPage;
}

@Controller
public class RankPageController {
    @RequestMapping(value = "/rankpage/{type}/{page}")
    public String rankPage(HttpServletRequest request, @PathVariable(value="type") String type, @PathVariable(value="page") String page, ModelMap modelMap) {
        String uuid = RequestHelper.getUserUUIDFromRequest(request);
        boolean isLogin = AccountHelper.isExistFromUUID(uuid);
        boolean isAdmin = AccountHelper.isAdminFromUUID(uuid);
        long unread = 0;
        String user = "";
        if (isLogin) {
            unread = NotifyHelper.countUnreadNotify(uuid);
            user = uuid;
        }
        StatisticHelper.addRankPageAccess(uuid, NetworkHelper.getIPAddress(request), TimeHelper.getFormattedNowString(), UserAgentHelper.getUserAgent(request));

        String baseUrl = UriHelper.getServerBaseUri(request);

        boolean isCrawl = UserAgentHelper.isCrawlFromRequestInfo(request);
        if (isCrawl) {
            return "error";
        }
        else {
            int querypage = Integer.parseInt(page);
            if (type.equals("zonghe") && querypage >= 10) {
                querypage = 9;
            }
            RankPageIndicator indicator = new RankPageIndicator();
            List<List<String>> contentList = processPage(uuid, type, querypage, indicator);

            int indexOfFirst = GlobalConfig.itemPerRankPage * querypage + 1;
            int indexOfLast = indexOfFirst + contentList.size() - 1;
            List<String[]> catlogList = CatlogHelper.getCatlogInfos(1);

            modelMap.put("siteName", GlobalConfig.siteName);
            modelMap.put("type", CatlogHelper.typeToString(type));
            modelMap.put("catlogList", catlogList);
            modelMap.put("indexOfFirst", ScoreHelper.getFormattedSecretScore((double) indexOfFirst));
            modelMap.put("indexOfLast", ScoreHelper.getFormattedSecretScore((double) indexOfLast));
            modelMap.put("totalPage", indicator.totalPage);
            modelMap.put("hasNext", indicator.hasNext);
            modelMap.put("hasPrevious", indicator.hasPrevious);
            modelMap.put("currentPage", page);
            modelMap.put("catlog", CatlogHelper.typeToString(type));
            modelMap.put("contentList", contentList);
            modelMap.put("isLogin", isLogin);
            modelMap.put("isAdmin", isAdmin);
            modelMap.put("serverUri", baseUrl);
            modelMap.put("unread", unread);
            modelMap.put("year2year", "2019 - " + TimeHelper.getFromattedCurrentYear());
            return "rankPage";
        }
    }

    private List<List<String>> processPage(String uuid, String type, int page, RankPageIndicator indicator) {
        FindIterable<Document> documents = findDocumentsFromType(type, page, indicator);
        List<List<String>> contentList = new ArrayList<>();
        int index = GlobalConfig.itemPerRankPage * page + 1;

        for (Document doc : documents) {
            List<String> childList = new ArrayList<>();

            String id = doc.get("_id").toString();
            String title = doc.get("title").toString();
            String catlog = doc.get("catlog").toString();
            String authorId = doc.get("author").toString();
            String author = AuthorHelper.getAuthorNameFromId(authorId);
            String score = ScoreHelper.getFormattedSecretScore((Double) doc.get("score"));

            childList.add(id);
            childList.add(title);
            childList.add(catlog);
            childList.add(author);
            childList.add(score);

            boolean collected = false;
            if (uuid == null || uuid.isEmpty()) {
                collected = false;
            }
            else {
                collected = CollectionHelper.checkUserCollection(uuid, id);
            }

            childList.add(collected ? "true" : "false");
            childList.add(ScoreHelper.getFormattedSecretScore((double) index++));
            contentList.add(childList);
        }

        return contentList;
    }

    private FindIterable<Document> findDocumentsFromType(String type, int page, RankPageIndicator indicator) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfArticle);

        Bson filter = CatlogHelper.typeToFilter(type);
        Document sortMethod = new Document("score", -1);
        filter = and(filter, eq("finished", true));

        //总共数量
        long count = collection.countDocuments(filter);
        if (type.equals("zonghe") && count > 100) {
            count = 100;
        }
        long totalPage = count / GlobalConfig.itemPerRankPage;
        if (count % GlobalConfig.itemPerRankPage != 0) {
            totalPage++;
        }

        indicator.totalPage = totalPage;

        computeIndicator(indicator, page, totalPage);

        return collection.find(filter).sort(sortMethod).skip(page * GlobalConfig.itemPerRankPage).limit(GlobalConfig.itemPerRankPage);
    }

    private void computeIndicator(RankPageIndicator indicator, long page, long totalPage) {
        long first = 0, last = totalPage - 1;

        if (page == first && page == last) {
            indicator.hasPrevious = false;
            indicator.hasNext = false;
        }
        else if (page == first) {
            indicator.hasPrevious = false;
            indicator.hasNext = true;
        }
        else if (page == last) {
            indicator.hasPrevious = true;
            indicator.hasNext = false;
        }
        else {
            indicator.hasPrevious = true;
            indicator.hasNext = true;
        }
    }
}
